/*
 * Copyright 2008-2023 dexian.vip. All rights reserved.
 * Support: http://www.dexian.vip
 * License: http://www.dexian.vip/license
 */

package vip.dexian.code.generator;

import vip.dexian.admin.entity.RoleDepartment;
import vip.dexian.code.config.ModelMap;
import vip.dexian.code.config.PathUtilsType;
import vip.dexian.code.config.Template;
import vip.dexian.code.config.TemplateUtils;
import vip.dexian.code.path.admin.AdminPathUtils;
import vip.dexian.common.utils.FreeMarkerUtils;
import freemarker.template.TemplateException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.tuple.Pair;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 生成代码
 */
@Slf4j
public class Generator {

    /**
     * ftl生成存放的目录， 存在目录的规则为 /admin/模块名称(下划线形式)/list、save、update、view等
     * <p>
     * 不同模块之间，需要修改该值
     */
    // 【修改】
    private static final String MODULE_DIRECTORY = "admin";

    public static void main (String[] args) {


        // 【修改】
        Class entityClass = RoleDepartment.class;
        // 【修改】 功能名称
        String entityComment = "角色->部门";

        // 【修改】文件路径类型
        PathUtilsType pathUtilsType = PathUtilsType.ADMIN;
        // 模块包名前缀
        String packagePrefix = pathUtilsType.getPackagePrefix();

        // =============== 以下的代码根据实际情况调整=======
        // 是否覆盖原文件
        boolean isOverride = false;

        // 是否写入权限
        boolean isWritePerms = false;

        // 是否生成页面
        boolean isWritePage = false;

        // 生成的页面类型
        PageType pageType = PageType.ALL;

        Pair <List <Template>, ModelMap> pair = TemplateUtils.builder().entityClass(entityClass).modelMap(entityComment)
                // dao
                .dao(isOverride, pathUtilsType)
                // dao impl
                .daoImpl(isOverride, pathUtilsType)
                // dto
                .dto(isOverride, pathUtilsType)
                // dto assembler
                .dtoMapper(isOverride, pathUtilsType)
                // service
                .service(isOverride, pathUtilsType)
                // service impl
                .serviceImpl(isOverride, pathUtilsType)
                // saveCommand
                //                .saveForm(isOverride, pathUtilsType)
                //                // updateCommand
                //                .updateForm(isOverride, pathUtilsType)
                //saveCommandAssembler，包含了添加修改
                //                .saveFormMapper(isOverride, pathUtilsType)
                // controller
                //                .controller(isOverride, pathUtilsType)
                // 分页查询
                //                .pageForm(isOverride, pathUtilsType)
                //                // 列表查询
                //                .listForm(isOverride, pathUtilsType)
                //
                .sql(isOverride, pathUtilsType)

                .build();

        List <Template> templates = pair.getLeft();

        ModelMap modelMap = pair.getRight();

        Map <String, Object> model = new HashMap <>();

        model.put("modelMap", modelMap);
        model.put("module", MODULE_DIRECTORY);
        model.put("packagePrefix", packagePrefix);

        for (Template template : templates) {

            Pair <Boolean, String> canWrite = template.canWrite();

            if (!canWrite.getLeft()) {
                System.err.println("template不可写入。" + canWrite.getRight());
                continue;
            }

            try {
                model.put(template.getTemplateKey(), template);

                String templateContent = templateContent(template.getTemplatePath());

                String processTemplateContent = FreeMarkerUtils.process(templateContent, model);

                // 写入的文件名称
                String fileName = template.getFileName();

                FileUtils.write(new File(fileName), processTemplateContent, StandardCharsets.UTF_8);

                System.out.println("写入" + fileName + "成功！");
            } catch (IOException | TemplateException e) {
                e.printStackTrace();
            }
        }

        if (isWritePerms) {
            writePermsYml(model);
            writePermsPage(model);
        }

        if (isWritePage) {
            writePage(model, pageType, isOverride);
        }
    }

    /**
     * 获取模板内容
     *
     * @param templatePath
     *         模板路径
     *
     * @return 返回模板的内容
     *
     * @throws java.io.IOException
     */
    private static String templateContent (String templatePath) throws IOException {

        File file = new File(templatePath);

        return FileUtils.readFileToString(file, "UTF-8");
    }

    /**
     * 写入权限yml
     *
     * @param model
     */
    private static void writePermsYml (Map <String, Object> model) {
        writePerms(model, AdminPathUtils.PERMS_YML_LOCATION, true);
    }

    /**
     * 写入权限page
     *
     * @param model
     */
    private static void writePermsPage (Map <String, Object> model) {
        writePerms(model, AdminPathUtils.PERMS_PAGE_LOCATION, false);
    }

    /**
     * 权限
     *
     * @param model
     * @param fileName
     */
    private static void writePerms (Map <String, Object> model, String fileName, boolean isYml) {
        File file = new File(fileName);

        try {
            String content = null;
            try {
                content = getPermsContent(isYml, model);
            } catch (TemplateException e) {
                e.printStackTrace();
            }

            FileUtils.write(file, content, StandardCharsets.UTF_8, true);

            System.out.println("写入" + (isYml ? "yml文件" : "权限页面") + "成功");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 权限
     *
     * @param isYml
     */
    private static String getPermsContent (boolean isYml, Map <String, Object> model)
            throws IOException, TemplateException {
        String basePath = Config.PROJECT_DIRECTORY + "/code-generator/src/main/java/vip/dexian/code/template/";

        String path = isYml ? basePath + "PermsYml.ftl" : basePath + "PermsPage.ftl";

        String templateContent = templateContent(path);

        String processTemplateContent = FreeMarkerUtils.process(templateContent, model);

        return processTemplateContent;
    }

    /**
     * 是否写入页面
     *
     * @param model
     */
    private static void writePage (Map <String, Object> model, PageType pageType, boolean isOverride) {

        ModelMap modelMap = (ModelMap) model.get("modelMap");

        // 文件目录
        String underline = modelMap.getUnderlineName();

        String directoryPath = AdminPathUtils.PAGES_LOCATION + MODULE_DIRECTORY + "/" + underline;

        File directory = new File(directoryPath);

        // 目录不存在，创建目录
        if (!directory.exists()) {
            directory.mkdirs();
        }

        switch (pageType) {
            case ALL:
                try {
                    writeList(model, directoryPath, isOverride);
                    writeSave(model, directoryPath, isOverride);
                    writeUpdate(model, directoryPath, isOverride);
                } catch (IOException | TemplateException e) {
                    e.printStackTrace();
                }
                return;
            case LIST:
                try {
                    writeList(model, directoryPath, isOverride);
                } catch (IOException | TemplateException e) {
                    e.printStackTrace();
                }
                return;
            case SAVE:
                try {
                    writeSave(model, directoryPath, isOverride);
                } catch (IOException | TemplateException e) {
                    e.printStackTrace();
                }
                return;
            case UPDATE:
                try {
                    writeUpdate(model, directoryPath, isOverride);
                } catch (IOException | TemplateException e) {
                    e.printStackTrace();
                }
                return;
            default:
        }

    }

    /**
     * 写入list
     *
     * @param model
     * @param directoryPath
     *
     * @throws java.io.IOException
     * @throws freemarker.template.TemplateException
     */
    private static void writeList (Map <String, Object> model, String directoryPath, boolean isOverride)
            throws IOException, TemplateException {
        String path = Config.PROJECT_DIRECTORY + "/code-generator/src/main/java/vip/dexian/code/template/list.ftl";

        String templateContent = templateContent(path);

        String processTemplateContent = FreeMarkerUtils.process(templateContent, model);

        File file = new File(directoryPath + "/" + "list.ftl");

        if (!isOverride && file.exists()) {
            System.out.println(file.getAbsolutePath() + "已存在，不可写入");
            return;
        }

        FileUtils.write(file, processTemplateContent, StandardCharsets.UTF_8);

        System.out.println((isOverride ? "覆盖" : "写入") + file.getAbsolutePath() + "页面成功");
    }

    /**
     * 写入list
     *
     * @param model
     * @param directoryPath
     *
     * @throws java.io.IOException
     * @throws freemarker.template.TemplateException
     */
    private static void writeSave (Map <String, Object> model, String directoryPath, boolean isOverride)
            throws IOException, TemplateException {
        String path = Config.PROJECT_DIRECTORY + "/code-generator/src/main/java/vip/dexian/code/template/save" + ".ftl";

        String templateContent = templateContent(path);

        String processTemplateContent = FreeMarkerUtils.process(templateContent, model);

        File file = new File(directoryPath + "/" + "save.ftl");

        if (!isOverride && file.exists()) {
            System.out.println(file.getAbsolutePath() + "已存在，不可写入");
            return;
        }

        FileUtils.write(file, processTemplateContent, StandardCharsets.UTF_8);

        System.out.println((isOverride ? "覆盖" : "写入") + file.getAbsolutePath() + "页面成功");
    }


    /**
     * 写入list
     *
     * @param model
     * @param directoryPath
     *
     * @throws java.io.IOException
     * @throws freemarker.template.TemplateException
     */
    private static void writeUpdate (Map <String, Object> model, String directoryPath, boolean isOverride)
            throws IOException, TemplateException {
        String path = Config.PROJECT_DIRECTORY + "/code-generator/src/main/java/vip/dexian/code/template" + "/update" + ".ftl";

        String templateContent = templateContent(path);

        String processTemplateContent = FreeMarkerUtils.process(templateContent, model);

        File file = new File(directoryPath + "/" + "update.ftl");

        if (!isOverride && file.exists()) {
            System.out.println(file.getAbsolutePath() + "已存在，不可写入");
            return;
        }

        FileUtils.write(file, processTemplateContent, StandardCharsets.UTF_8);

        System.out.println((isOverride ? "覆盖" : "写入") + file.getAbsolutePath() + "页面成功");
    }


    public enum PageType {
        /**
         * 全部
         */
        ALL,

        /**
         * 列表
         */
        LIST,
        /**
         * 保存
         */
        SAVE,
        /**
         * 更新
         */
        UPDATE,
    }
}
